﻿using System.Collections;
using System.Collections.Generic;
using Magiq.Support;
using Magiq.Tests.Support;
using NUnit.Framework;

namespace Magiq.Tests {
  [TestFixture]
  public class ReflectionTests {
    #region Setup/Teardown

    [SetUp]
    public void SetUp() {
      instance = new TestClass
                   {
                     InterfaceProperty = new List<int>(),
                     ValueProperty = 3,
                     NullableProperty = 3,
                     ObjectProperty = "bla",
                     ClassProperty = "bla"
                   };
      nullInstance = new TestClass();
    }

    #endregion

    private TestClass instance;
    private TestClass nullInstance;

    private class TestClass {
      private string classField;
      public string ClassProperty {
        get { return classField; }
        set { classField = value; }
      }

      private int valueField;
      public int ValueProperty {
        get { return valueField; }
        set { valueField = value; }
      }

      private int? nullableField;
      public int? NullableProperty {
        get { return nullableField; }
        set { nullableField = value; }
      }

      private object objectField;
      public object ObjectProperty {
        get { return objectField; }
        set { objectField = value; }
      }

      private IEnumerable interfaceField;
      public IEnumerable InterfaceProperty {
        get { return interfaceField; }
        set { interfaceField = value; }
      }
    }

    [Test]
    public void ShouldGetClassFields() {
      instance.Field("classField").Should(Be.EqualTo(instance.ClassProperty));
    }

    [Test]
    public void ShouldGetClassPropertys() {
      instance.Property("ClassProperty").Should(Be.EqualTo(instance.ClassProperty));
    }

    [Test]
    public void ShouldGetInterfaceFields() {
      instance.Field("interfaceField").Should(Be.EqualTo(instance.InterfaceProperty));
    }

    [Test]
    public void ShouldGetInterfacePropertys() {
      instance.Property("InterfaceProperty").Should(Be.EqualTo(instance.InterfaceProperty));
    }

    [Test]
    public void ShouldGetNullableFields() {
      instance.Field("nullableField").Should(Be.EqualTo(instance.NullableProperty));
    }

    [Test]
    public void ShouldGetNullablePropertys() {
      instance.Property("NullableProperty").Should(Be.EqualTo(instance.NullableProperty));
    }

    [Test]
    public void ShouldGetNullClassFields() {
      nullInstance.Field("classField").Should(Be.EqualTo(nullInstance.ClassProperty));
    }

    [Test]
    public void ShouldGetNullClassPropertys() {
      nullInstance.Property("ClassProperty").Should(Be.EqualTo(nullInstance.ClassProperty));
    }

    [Test]
    public void ShouldGetNullInterfaceFields() {
      nullInstance.Field("interfaceField").Should(Be.EqualTo(nullInstance.InterfaceProperty));
    }

    [Test]
    public void ShouldGetNullInterfacePropertys() {
      nullInstance.Property("InterfaceProperty").Should(Be.EqualTo(nullInstance.InterfaceProperty));
    }

    [Test]
    public void ShouldGetNullNullableFields() {
      nullInstance.Field("nullableField").Should(Be.EqualTo(nullInstance.NullableProperty));
    }

    [Test]
    public void ShouldGetNullNullablePropertys() {
      nullInstance.Property("NullableProperty").Should(Be.EqualTo(nullInstance.NullableProperty));
    }

    [Test]
    public void ShouldGetNullObjectFields() {
      nullInstance.Field("objectField").Should(Be.EqualTo(nullInstance.ObjectProperty));
    }

    [Test]
    public void ShouldGetNullObjectPropertys() {
      nullInstance.Property("ObjectProperty").Should(Be.EqualTo(nullInstance.ObjectProperty));
    }

    [Test]
    public void ShouldGetObjectFields() {
      instance.Field("objectField").Should(Be.EqualTo(instance.ObjectProperty));
    }

    [Test]
    public void ShouldGetObjectPropertys() {
      instance.Property("ObjectProperty").Should(Be.EqualTo(instance.ObjectProperty));
    }

    [Test]
    public void ShouldGetValueFields() {
      instance.Field("valueField").Should(Be.EqualTo(instance.ValueProperty));
    }

    [Test]
    public void ShouldGetValuePropertys() {
      instance.Property("ValueProperty").Should(Be.EqualTo(instance.ValueProperty));
    }

    [Test]
    public void ShouldSetClassProperties() {
      nullInstance.SetProperty("ClassProperty", "lala");
      nullInstance.ClassProperty.Should(Be.EqualTo("lala"));
    }

    [Test]
    public void ShouldSetInterfaceProperties() {
      var value = new List<int>();
      nullInstance.SetProperty("InterfaceProperty", value);
      nullInstance.InterfaceProperty.Should(Be.EqualTo(value));
    }

    [Test]
    public void ShouldSetNullableProperties() {
      nullInstance.SetProperty("NullableProperty", 3);
      nullInstance.NullableProperty.Should(Be.EqualTo(3));
    }

    [Test]
    public void ShouldSetNullClassProperties() {
      nullInstance.SetProperty("ClassProperty", null);
      nullInstance.ClassProperty.Should(Be.Null);
    }

    [Test]
    public void ShouldSetNullInterfaceProperties() {
      nullInstance.SetProperty("InterfaceProperty", null);
      nullInstance.ClassProperty.Should(Be.Null);
    }

    [Test]
    public void ShouldSetNullNullableProperties() {
      nullInstance.SetProperty("NullableProperty", null);
      nullInstance.NullableProperty.Should(Be.Null);
    }

    [Test]
    public void ShouldSetNullObjectProperties() {
      nullInstance.SetProperty("ObjectProperty", null);
      nullInstance.ClassProperty.Should(Be.Null);
    }

    [Test]
    public void ShouldSetObjectProperties() {
      var value = new List<int>();
      nullInstance.SetProperty("ObjectProperty", value);
      nullInstance.ObjectProperty.Should(Be.EqualTo(value));
    }

    [Test]
    public void ShouldSetValueProperties() {
      nullInstance.SetProperty("ValueProperty", 1);
      nullInstance.ValueProperty.Should(Be.EqualTo(1));
    }
  }
}